/**
 * Copyright (c) 2009 blurredVision
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 
 * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include "StdAfx.h"
#include "../guidefaults.h"
#include "../TextBox.h"

namespace gui {

	bool TextBox::s_bInTextBox = false;

TextBox::TextBox(const std::string &text, eTextAlign align)
:	Label(text, align), 
	uiTextLength(20),
	uiNumberOfLines(1),
	iMaxRows(-1),
	stringFunction(NULL),
	bInput(false),
	m_bClearOnFirstKey(false),
	m_uiDrawCursorOffset(0),
	m_bShowCursor(true)
{
	stringOutput.clear();
	stringStream.clear();
	uiCursorPosition = static_cast<unsigned int>( text.length() );
	updateCursorOffset();
}

TextBox::~TextBox(void)
{
	stringStream.str("");
	stringStream.clear();
	stringOutput.clear();
}

void TextBox::updateCursorOffset()
{
	m_uiDrawCursorOffset = font->getLength( m_sText.substr(0, uiCursorPosition)) + 1;
}

void TextBox::setStringFunction( std::string(*fp)(const std::string&) )
{
	stringFunction = fp;
}

void TextBox::winMsgProc( UINT uMsg, WPARAM wParam, LPARAM lParam )
{	
	if ( bInput ) {
		switch (uMsg) 
		{
			case WM_CHAR:		
				if (wParam == 13) {						// RETURN
					if(stringFunction) {
						m_sText = stringFunction(m_sText);
						if(m_sText != "") {
							display(m_sText);
							m_sText.clear();
						}
					}
					//m_sText.clear(); /// TODO fuer Multiline muss hier noch ein clear hin...
					s_bInTextBox = false;
					bInput = false;
					valueChanged(this);
				}
				else if (wParam == 27) {					// ESC					
					activeComponent = NULL;
					unsetFocus();
				}					
				else if (wParam == VK_TAB) { }					// TAB
				// delete before cursor position
				else if (wParam == VK_BACK) {					// BACKSPACE
					if (m_sText.size() > 0 && uiCursorPosition > 0) {
						m_sText.erase(uiCursorPosition-1, 1);
						--uiCursorPosition;
					}
				}
				// Insert a new character
				else {
					unsigned char key = (unsigned char) wParam;
					char ch[2];
					memcpy((void*)ch, &key, 1);
					if (m_sText.size() < uiTextLength) {
						m_sText.insert(uiCursorPosition, ch, 1);
						++uiCursorPosition;
					}
				}
				updateCursorOffset();
				Component::ExecUpdate();

				break;
			
			case WM_KEYDOWN:
				if (m_bClearOnFirstKey) {
					setText("");
					m_bClearOnFirstKey = false;
				}
				// Move cursor position left
				if (wParam == VK_LEFT) {
					if (uiCursorPosition >0)
						--uiCursorPosition;			 
				}
				// Move cursor position right
				else if (wParam == VK_RIGHT) {
					if (uiCursorPosition < m_sText.size())
						++uiCursorPosition;
				}
				// Delete after cursor position
				else if (wParam == VK_DELETE) {
					if (m_sText.size() > 0 && uiCursorPosition < m_sText.size()) {
						m_sText.erase(uiCursorPosition, 1);
					}
				}
				// Move cursor position to end of line
				else if (wParam == VK_END) {
					uiCursorPosition = static_cast<unsigned int>( m_sText.size() );
				}
				// Move cursor position to begin of line
				else if (wParam == VK_HOME) {
					uiCursorPosition = 0;
				}
				updateCursorOffset();
				Component::ExecUpdate();
				break;
		}
	}
	/// Pass the messages to sub items
	Component::winMsgProc( uMsg, wParam, lParam );
}

void TextBox::display(const std::string &_str)
{
	// Add String to stringOutput
	stringOutput.insert(stringOutput.begin(), _str);
	
	if(stringOutput.size() == 2*uiNumberOfLines) {
		stringOutput.erase(--stringOutput.end());
	}
	Component::ExecUpdate();
}

void TextBox::setNumberOfLines(int _nl)
{
	// Set the number of lines to display
	uiNumberOfLines = _nl;
	vDim.y = iRowSize * uiNumberOfLines; 
}

void TextBox::setDimension(int x, int y, int w, int h)
{
	vDim.y = iRowSize * uiNumberOfLines;
	Component::setDimension(x,y,w, vDim.y);
}

void TextBox::setInput(bool _val)
{
	if(!_val) {
		// Deselect. Change the value
		triggerChange();
	}
	bInput = _val;
	Component::ExecUpdate();
}

const bool TextBox::getInput() const
{
	return bInput;
}

void TextBox::onMousePressed(const MouseEvent &me)
{
	Component::onMousePressed(me);
	bInput = true;
	s_bInTextBox = true;
}

void TextBox::setText(const std::string &text)
{
	Label::setText(text);
	uiCursorPosition = static_cast<unsigned int>(m_sText.size());
	updateCursorOffset();
	Component::ExecUpdate();
}

void TextBox::setTextLength(unsigned int length)
{
	uiTextLength = length;
}

unsigned int TextBox::getTextLength() const 
{
	return uiTextLength;
}

void TextBox::displayString(const std::string &_str)
{
	display(_str);
}

void TextBox::draw() 
{
	gui_list::iterator str;
	std::string line;

	if (stringStream.str().size() > 0) {
		stringStream.seekg( 0, std::ios_base::beg );
		while (std::getline(stringStream, line)) {
			display(line);
		}
		stringStream.str("");
		stringStream.clear();
	}
	
	if (bVisible) {
		vRealPos = getAbsolutePosition();
		// Draw the background
		pRenderer->drawFilledRect(vRealPos.x , vRealPos.y, vDim.x, vDim.y, vBackColor);
		// Draw the rect
		pRenderer->drawRect(vRealPos.x , vRealPos.y, vDim.x, vDim.y, vBorderColor);
		// Draw the highlight if active
		if (activeComponent == this) 
			pRenderer->drawRect(vRealPos.x-1, vRealPos.y-1, vDim.x+2, vDim.y+2, vBorderColor);

		// Draw the current line
		font->print(m_sText, vRealPos.x+vOffset.x , (vRealPos.y+vOffset.x)+iRowSize*(uiNumberOfLines-1), 0, FONT_LEFT, vDim.x, vDim.y, vTextColor);

		// Draw the cursor
		if (bInput && m_bShowCursor)
			pRenderer->drawRect(vRealPos.x + m_uiDrawCursorOffset, vRealPos.y+2, 1, vDim.y-4, vBorderColor);

		int i = uiNumberOfLines-2;

		for(str = stringOutput.begin(); (str != stringOutput.end()); ++str) {
			// TODO Insert colors for rows, other than the input row
			font->print(*str, vRealPos.x+vOffset.x, (vRealPos.y+vOffset.y)+(iRowSize*i));
			// Return if the  number of lines is reached
			if (--i <= 0) return;
		}
	}
}

void TextBox::setFocus() 
{
	setInput(true);
}

void TextBox::unsetFocus() 
{
	setInput(false);
}

std::stringstream* TextBox::getStream() const
{
	return (std::stringstream*)&stringStream;
}


void TextBox::triggerChange()
{
	valueChanged(this);
}

void TextBox::setClearOnFirstKey(bool value)
{
	m_bClearOnFirstKey = value;
}

void TextBox::setShowCursor(bool value)
{
	m_bShowCursor = value;
}

void TextBox::setFont(IFont* pFont)
{
	Component::setFont(pFont);
	updateCursorOffset();
}

const bool TextBox::InTextBox()
{
	return s_bInTextBox;
}

void TextBox::InTextBox(bool val)
{
	s_bInTextBox = val;
}

} // namespace
